﻿#region MIT Licence
/*
 * Copyright (C) 2014 PdfCreative
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
 * and associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom 
 * the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included 
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 
 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#endregion

using System;
using System.Collections.Generic;
using System.Text;

namespace PdfCreative.Pdf.Graphics
{
    /// <summary>
    /// The Cmyk class is a static convenience class that contains read-made pens, brushes and colours that
    /// use the Cmyk colour space.
    /// </summary>
    public static class Cmyk
    {
        // Private fields
        // ==============
        #region Private fields
        private static SolidBrush[] _brushes;
        private static CmykColour[] _colours;
        private static Pen[] _pens;
        #endregion



        // Public properties
        // =================
        #region Colours
        /// <summary>
        /// Retrieves a bright red colour.
        /// </summary>
        public static CmykColour Red { get { return _colours[(int)ColourCode.Red]; } }

        /// <summary>
        /// Retrieves a bright green colour.
        /// </summary>
        public static CmykColour Green { get { return _colours[(int)ColourCode.Green]; } }

        /// <summary>
        /// Retrieves a bright yellow colour.
        /// </summary>
        public static CmykColour Yellow { get { return _colours[(int)ColourCode.Yellow]; } }

        /// <summary>
        /// Retrieves a bright blue colour.
        /// </summary>
        public static CmykColour Blue { get { return _colours[(int)ColourCode.Blue]; } }

        /// <summary>
        /// Retrieves a bright magenta colour.
        /// </summary>
        public static CmykColour Magenta { get { return _colours[(int)ColourCode.Magenta]; } }

        /// <summary>
        /// Retrieves a bright cyan colour.
        /// </summary>
        public static CmykColour Cyan { get { return _colours[(int)ColourCode.Cyan]; } }

        /// <summary>
        /// Retrieves a white colour.
        /// </summary>
        public static CmykColour White { get { return _colours[(int)ColourCode.White]; } }

        /// <summary>
        /// Retrieves a black colour.
        /// </summary>
        public static CmykColour Black { get { return _colours[(int)ColourCode.Black]; } }

        /// <summary>
        /// Retrieves a dark red colour.
        /// </summary>
        public static CmykColour DarkRed { get { return _colours[(int)ColourCode.DarkRed]; } }

        /// <summary>
        /// Retrieves a dark green colour.
        /// </summary>
        public static CmykColour DarkGreen { get { return _colours[(int)ColourCode.DarkGreen]; } }

        /// <summary>
        /// Retrieves a dark yellow colour.
        /// </summary>
        public static CmykColour DarkYellow { get { return _colours[(int)ColourCode.DarkYellow]; } }

        /// <summary>
        /// Retrieves a dark blue colour.
        /// </summary>
        public static CmykColour DarkBlue { get { return _colours[(int)ColourCode.DarkBlue]; } }

        /// <summary>
        /// Retrieves a dark magenta colour.
        /// </summary>
        public static CmykColour DarkMagenta { get { return _colours[(int)ColourCode.DarkMagenta]; } }

        /// <summary>
        /// Retrieves a dark cyan colour.
        /// </summary>
        public static CmykColour DarkCyan { get { return _colours[(int)ColourCode.DarkCyan]; } }

        /// <summary>
        /// Retrieves a grey colour that is 90% white, 10% black.
        /// </summary>
        public static CmykColour Grey90 { get { return _colours[(int)ColourCode.Grey90]; } }

        /// <summary>
        /// Retrieves a grey colour that is 80% white, 20% black.
        /// </summary>
        public static CmykColour Grey80 { get { return _colours[(int)ColourCode.Grey80]; } }

        /// <summary>
        /// Retrieves a grey colour that is 70% white, 30% black.
        /// </summary>
        public static CmykColour Grey70 { get { return _colours[(int)ColourCode.Grey70]; } }

        /// <summary>
        /// Retrieves a grey colour that is 60% white, 40% black.
        /// </summary>
        public static CmykColour Grey60 { get { return _colours[(int)ColourCode.Grey60]; } }

        /// <summary>
        /// Retrieves a grey colour that is half white, half black.
        /// </summary>
        public static CmykColour Grey50 { get { return _colours[(int)ColourCode.Grey50]; } }

        /// <summary>
        /// Retrieves a grey colour that is 40% white, 60% black.
        /// </summary>
        public static CmykColour Grey40 { get { return _colours[(int)ColourCode.Grey40]; } }

        /// <summary>
        /// Retrieves a grey colour that is 30% white, 70% black.
        /// </summary>
        public static CmykColour Grey30 { get { return _colours[(int)ColourCode.Grey30]; } }

        /// <summary>
        /// Retrieves a grey colour that is 20% white, 80% black.
        /// </summary>
        public static CmykColour Grey20 { get { return _colours[(int)ColourCode.Grey20]; } }

        /// <summary>
        /// Retrieves a grey colour that is 10% white, 90% black.
        /// </summary>
        public static CmykColour Grey10 { get { return _colours[(int)ColourCode.Grey10]; } }
        #endregion

        #region Pens
        /// <summary>
        /// Retrieves a bright red pen.
        /// </summary>
        public static Pen RedPen { get { return _pens[(int)ColourCode.Red]; } }

        /// <summary>
        /// Retrieves a bright green pen.
        /// </summary>
        public static Pen GreenPen { get { return _pens[(int)ColourCode.Green]; } }

        /// <summary>
        /// Retrieves a bright yellow pen.
        /// </summary>
        public static Pen YellowPen { get { return _pens[(int)ColourCode.Yellow]; } }

        /// <summary>
        /// Retrieves a bright blue pen.
        /// </summary>
        public static Pen BluePen { get { return _pens[(int)ColourCode.Blue]; } }

        /// <summary>
        /// Retrieves a bright magenta pen.
        /// </summary>
        public static Pen MagentaPen { get { return _pens[(int)ColourCode.Magenta]; } }

        /// <summary>
        /// Retrieves a bright cyan pen.
        /// </summary>
        public static Pen CyanPen { get { return _pens[(int)ColourCode.Cyan]; } }

        /// <summary>
        /// Retrieves a white pen.
        /// </summary>
        public static Pen WhitePen { get { return _pens[(int)ColourCode.White]; } }

        /// <summary>
        /// Retrieves a white pen.
        /// </summary>
        public static Pen BlackPen { get { return _pens[(int)ColourCode.Black]; } }

        /// <summary>
        /// Retrieves a dark red pen.
        /// </summary>
        public static Pen DarkRedPen { get { return _pens[(int)ColourCode.DarkRed]; } }

        /// <summary>
        /// Retrieves a dark green pen.
        /// </summary>
        public static Pen DarkGreenPen { get { return _pens[(int)ColourCode.DarkGreen]; } }

        /// <summary>
        /// Retrieves a dark yellow pen.
        /// </summary>
        public static Pen DarkYellowPen { get { return _pens[(int)ColourCode.DarkYellow]; } }

        /// <summary>
        /// Retrieves a dark blue pen.
        /// </summary>
        public static Pen DarkBluePen { get { return _pens[(int)ColourCode.DarkBlue]; } }

        /// <summary>
        /// Retrieves a dark magenta pen.
        /// </summary>
        public static Pen DarkMagentaPen { get { return _pens[(int)ColourCode.DarkMagenta]; } }

        /// <summary>
        /// Retrieves a dark cyan pen.
        /// </summary>
        public static Pen DarkCyanPen { get { return _pens[(int)ColourCode.DarkCyan]; } }

        /// <summary>
        /// Retrieves a grey pen that is 90% white, 10% black.
        /// </summary>
        public static Pen Grey90Pen { get { return _pens[(int)ColourCode.Grey90]; } }

        /// <summary>
        /// Retrieves a grey pen that is 80% white, 20% black.
        /// </summary>
        public static Pen Grey80Pen { get { return _pens[(int)ColourCode.Grey80]; } }

        /// <summary>
        /// Retrieves a grey pen that is 70% white, 30% black.
        /// </summary>
        public static Pen Grey70Pen { get { return _pens[(int)ColourCode.Grey70]; } }

        /// <summary>
        /// Retrieves a grey pen that is 60% white, 40% black.
        /// </summary>
        public static Pen Grey60Pen { get { return _pens[(int)ColourCode.Grey60]; } }

        /// <summary>
        /// Retrieves a grey pen that is half white, half black.
        /// </summary>
        public static Pen Grey50Pen { get { return _pens[(int)ColourCode.Grey50]; } }

        /// <summary>
        /// Retrieves a grey pen that is 40% white, 60% black.
        /// </summary>
        public static Pen Grey40Pen { get { return _pens[(int)ColourCode.Grey40]; } }

        /// <summary>
        /// Retrieves a grey pen that is 30% white, 70% black.
        /// </summary>
        public static Pen Grey30Pen { get { return _pens[(int)ColourCode.Grey30]; } }

        /// <summary>
        /// Retrieves a grey pen that is 20% white, 80% black.
        /// </summary>
        public static Pen Grey20Pen { get { return _pens[(int)ColourCode.Grey20]; } }

        /// <summary>
        /// Retrieves a grey pen that is 10% white, 90% black.
        /// </summary>
        public static Pen Grey10Pen { get { return _pens[(int)ColourCode.Grey10]; } }
        #endregion

        #region Brushes
        /// <summary>
        /// Retrieves a bright red brush.
        /// </summary>
        public static SolidBrush RedBrush { get { return _brushes[(int)ColourCode.Red]; } }

        /// <summary>
        /// Retrieves a bright green brush.
        /// </summary>
        public static SolidBrush GreenBrush { get { return _brushes[(int)ColourCode.Green]; } }

        /// <summary>
        /// Retrieves a bright yellow brush.
        /// </summary>
        public static SolidBrush YellowBrush { get { return _brushes[(int)ColourCode.Yellow]; } }

        /// <summary>
        /// Retrieves a bright blue brush.
        /// </summary>
        public static SolidBrush BlueBrush { get { return _brushes[(int)ColourCode.Blue]; } }

        /// <summary>
        /// Retrieves a bright magenta brush.
        /// </summary>
        public static SolidBrush MagentaBrush { get { return _brushes[(int)ColourCode.Magenta]; } }

        /// <summary>
        /// Retrieves a bright cyan brush.
        /// </summary>
        public static SolidBrush CyanBrush { get { return _brushes[(int)ColourCode.Cyan]; } }

        /// <summary>
        /// Retrieves a white brush.
        /// </summary>
        public static SolidBrush WhiteBrush { get { return _brushes[(int)ColourCode.White]; } }

        /// <summary>
        /// Retrieves a white brush.
        /// </summary>
        public static SolidBrush BlackBrush { get { return _brushes[(int)ColourCode.Black]; } }

        /// <summary>
        /// Retrieves a dark red brush.
        /// </summary>
        public static SolidBrush DarkRedBrush { get { return _brushes[(int)ColourCode.DarkRed]; } }

        /// <summary>
        /// Retrieves a dark green brush.
        /// </summary>
        public static SolidBrush DarkGreenBrush { get { return _brushes[(int)ColourCode.DarkGreen]; } }

        /// <summary>
        /// Retrieves a dark yellow brush.
        /// </summary>
        public static SolidBrush DarkYellowBrush { get { return _brushes[(int)ColourCode.DarkYellow]; } }

        /// <summary>
        /// Retrieves a dark blue brush.
        /// </summary>
        public static SolidBrush DarkBlueBrush { get { return _brushes[(int)ColourCode.DarkBlue]; } }

        /// <summary>
        /// Retrieves a dark magenta brush.
        /// </summary>
        public static SolidBrush DarkMagentaBrush { get { return _brushes[(int)ColourCode.DarkMagenta]; } }

        /// <summary>
        /// Retrieves a dark cyan brush.
        /// </summary>
        public static SolidBrush DarkCyanBrush { get { return _brushes[(int)ColourCode.DarkCyan]; } }

        /// <summary>
        /// Retrieves a grey brush that is 90% white, 10% black.
        /// </summary>
        public static SolidBrush Grey90Brush { get { return _brushes[(int)ColourCode.Grey90]; } }

        /// <summary>
        /// Retrieves a grey brush that is 80% white, 20% black.
        /// </summary>
        public static SolidBrush Grey80Brush { get { return _brushes[(int)ColourCode.Grey80]; } }

        /// <summary>
        /// Retrieves a grey brush that is 70% white, 30% black.
        /// </summary>
        public static SolidBrush Grey70Brush { get { return _brushes[(int)ColourCode.Grey70]; } }

        /// <summary>
        /// Retrieves a grey brush that is 60% white, 40% black.
        /// </summary>
        public static SolidBrush Grey60Brush { get { return _brushes[(int)ColourCode.Grey60]; } }

        /// <summary>
        /// Retrieves a grey brush that is half white, half black.
        /// </summary>
        public static SolidBrush Grey50Brush { get { return _brushes[(int)ColourCode.Grey50]; } }

        /// <summary>
        /// Retrieves a grey brush that is 40% white, 60% black.
        /// </summary>
        public static SolidBrush Grey40Brush { get { return _brushes[(int)ColourCode.Grey40]; } }

        /// <summary>
        /// Retrieves a grey brush that is 30% white, 70% black.
        /// </summary>
        public static SolidBrush Grey30Brush { get { return _brushes[(int)ColourCode.Grey30]; } }

        /// <summary>
        /// Retrieves a grey brush that is 20% white, 80% black.
        /// </summary>
        public static SolidBrush Grey20Brush { get { return _brushes[(int)ColourCode.Grey20]; } }

        /// <summary>
        /// Retrieves a grey brush that is 10% white, 90% black.
        /// </summary>
        public static SolidBrush Grey10Brush { get { return _brushes[(int)ColourCode.Grey10]; } }
        #endregion



        // Private implementation
        // ======================
        #region Private implementation
        /// <summary>
        /// Retrieves the colour specification of a colour code. The colour specification is represented
        /// by the CmykColour attribute that decorates the fields of the ColourCode enumeration.
        /// </summary>
        /// <param name="colourCode">The colour code.</param>
        /// <returns>The colour specification.</returns>
        private static CmykColourAttribute GetColourSpecification(ColourCode colourCode)
        {
            CmykColourAttribute result = null;

            System.Reflection.FieldInfo fieldInfo = colourCode.GetType().GetField(colourCode.ToString());
            foreach (CmykColourAttribute attr in fieldInfo.GetCustomAttributes(typeof(CmykColourAttribute), true))
            {
                result = attr; break;
            }

            return result;
        }

        /// <summary>
        /// Sets up the stock objects that can be retrieved from the Cmyk class.
        /// </summary>
        private static void SetupStockObjects()
        {
            int count = Enum.GetValues(typeof(ColourCode)).Length;
            
            _colours = new CmykColour[count];
            _pens = new Pen[count];
            _brushes = new SolidBrush[count];

            for (int colour = 0; colour < count; colour++)
            {
                // Retrieve the colour specification for this colour.
                CmykColourAttribute colourSpec = GetColourSpecification((ColourCode)colour);

                // Create the colour, and a pen and brush that match it.
                _colours[colour] = new CmykColour(colourSpec.Cyan, colourSpec.Magenta, colourSpec.Yellow, colourSpec.Key);
                _pens[colour] = new Pen(_colours[colour], 0.25f);
                _brushes[colour] = new SolidBrush(_colours[colour]);
            }
        }
        #endregion



        // Private constructor
        // ===================
        #region Private constructor
        /// <summary>
        /// Sets up the Cmyk static class.
        /// </summary>
        static Cmyk()
        {
            SetupStockObjects();
        }
        #endregion



        // Private types
        // =============
        #region ColourCode enumeration
        /// <summary>
        /// The ColourCode enumeration lists the colours of the stock objects that can be retrieved from the
        /// Cmyk class.
        /// </summary>
        private enum ColourCode
        {
            [CmykColour(Cyan = 191, Magenta = 173, Yellow = 171, Key = 230)]
            Black,

            [CmykColour(Cyan = 0, Magenta = 255, Yellow = 255, Key = 0)]
            Red,

            [CmykColour(Cyan = 161, Magenta = 0, Yellow = 255, Key = 0)]
            Green,

            [CmykColour(Cyan = 0, Magenta = 0, Yellow = 255, Key = 0)]
            Yellow,

            [CmykColour(Cyan = 224, Magenta = 196, Yellow = 0, Key = 0)]
            Blue,

            [CmykColour(Cyan = 69, Magenta = 209, Yellow = 0, Key = 0)]
            Magenta,

            [CmykColour(Cyan = 133, Magenta = 0, Yellow = 33, Key = 0)]
            Cyan,

            [CmykColour(Cyan = 0, Magenta = 0, Yellow = 0, Key = 0)]
            White,

            [CmykColour(Cyan = 74, Magenta = 255, Yellow = 255, Key = 97)]
            DarkRed,

            [CmykColour(Cyan = 222, Magenta = 64, Yellow = 255, Key = 33)]
            DarkGreen,

            [CmykColour(Cyan = 130, Magenta = 92, Yellow = 255, Key = 36)]
            DarkYellow,

            [CmykColour(Cyan = 255, Magenta = 250, Yellow = 36, Key = 43)]
            DarkBlue,

            [CmykColour(Cyan = 156, Magenta = 255, Yellow = 36, Key = 10)]
            DarkMagenta,

            [CmykColour(Cyan = 222, Magenta = 82, Yellow = 125, Key = 23)]
            DarkCyan,

            [CmykColour(Cyan = 23, Magenta = 15, Yellow = 18, Key = 0)]
            Grey90,

            [CmykColour(Cyan = 48, Magenta = 38, Yellow = 41, Key = 0)]
            Grey80,

            [CmykColour(Cyan = 79, Magenta = 64, Yellow = 64, Key = 0)]
            Grey70,

            [CmykColour(Cyan = 110, Magenta = 89, Yellow = 89, Key = 3)]
            Grey60,

            [CmykColour(Cyan = 133, Magenta = 112, Yellow = 112, Key = 20)]
            Grey50,

            [CmykColour(Cyan = 153, Magenta = 130, Yellow = 130, Key = 51)]
            Grey40,

            [CmykColour(Cyan = 166, Magenta = 148, Yellow = 145, Key = 94)]
            Grey30,

            [CmykColour(Cyan = 176, Magenta = 161, Yellow = 158, Key = 148)]
            Grey20,

            [CmykColour(Cyan = 186, Magenta = 171, Yellow = 166, Key = 201)]
            Grey10
        }
        #endregion

        #region CmykColourAttribute class
        /// <summary>
        /// The CmykColourAttribute class represent the CmykColour attribute that is used to decorate fields
        /// of the ColourCode enumeration. It links a ColourCode field to a colour expressed in the Cmyk
        /// colour space.
        /// </summary>
        [AttributeUsage(AttributeTargets.Field)]
        private class CmykColourAttribute : Attribute
        {
            // Private fields
            // ==============
            #region Private fields
            private byte _cyan;
            private byte _magenta;
            private byte _yellow;
            private byte _key;
            #endregion



            // Public properties
            // =================
            #region Public properties
            /// <summary>
            /// Sets or retrieves the cyan component of the colour.
            /// </summary>
            public byte Cyan
            {
                get { return _cyan; }
                set { _cyan = value; }
            }

            /// <summary>
            /// Sets or retrieves the magenta component of the colour.
            /// </summary>
            public byte Magenta
            {
                get { return _magenta; }
                set { _magenta = value; }
            }

            /// <summary>
            /// Sets or retrieves the yellow component of the colour.
            /// </summary>
            public byte Yellow
            {
                get { return _yellow; }
                set { _yellow = value; }
            }

            /// <summary>
            /// Sets or retrieves the key component of the colour.
            /// </summary>
            public byte Key
            {
                get { return _key; }
                set { _key = value; }
            }
            #endregion

        } // CmykColourAttribute class
        #endregion

    } // Cmyk class
}
